﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Interop.Word;

namespace TemplateAddIn
{
    public partial class ThisAddIn
    {
        #region Events
        public event VariableEvent VariableModified;
        public event VariableEvent VariableAdded;
        public event VariableEvent VariableRemoved;
        public event VariableEvent VariableFieldSelected;
        #endregion

        #region Fields
        public List<Word.ContentControl>
            ccList;

        private VariableList<Variable>
            varList;

        private Dictionary<Word.Document, VariableList<Variable>>
            varLists;

        private bool
            HandleContentControlOnExitEvent = true;

        #endregion

        #region Properties
        public VariableList<Variable> VarList
        {
            get
            {
                if (varList == null)
                    varList = new VariableList<Variable>();

                return varList;
            }
            set { varList = value; }
        }

        public Dictionary<Word.Document, VariableList<Variable>> VarLists
        {
            get
            {
                if (varLists == null)
                    varLists = new Dictionary<Word.Document, VariableList<Variable>>();

                return varLists;
            }
            set { varLists = value; }
        }
        #endregion

        #region AddIn Events
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }
        #endregion

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);

            //Handlers para tratar múltiplos documentos
            this.Application.DocumentOpen += new Microsoft.Office.Interop.Word.ApplicationEvents4_DocumentOpenEventHandler(Application_DocumentOpen);
            this.Application.DocumentChange += new Microsoft.Office.Interop.Word.ApplicationEvents4_DocumentChangeEventHandler(Application_DocumentChange);
            this.Application.DocumentBeforeClose += new Microsoft.Office.Interop.Word.ApplicationEvents4_DocumentBeforeCloseEventHandler(Application_DocumentBeforeClose);

            //Handlers para tratar a seleção das variáveis na UI
            this.Application.ActiveDocument.ContentControlOnEnter += new Microsoft.Office.Interop.Word.DocumentEvents2_ContentControlOnEnterEventHandler(ActiveDocument_ContentControlOnEnter);
            this.Application.ActiveDocument.ContentControlOnExit += new Microsoft.Office.Interop.Word.DocumentEvents2_ContentControlOnExitEventHandler(ActiveDocument_ContentControlOnExit);
        }

        #endregion

        #region VarList Events
        void VarList_ItemAdded(Variable var)
        {
            if (VariableAdded != null)
                VariableAdded(var);
        }

        void VarList_ItemRemoved(Variable var)
        {
            if (VariableRemoved != null)
                VariableRemoved(var);
        }
        #endregion

        #region Word Events
        void ActiveDocument_ContentControlOnEnter(Microsoft.Office.Interop.Word.ContentControl ContentControl)
        {
            if (VariableFieldSelected != null)
                VariableFieldSelected(VarList[ContentControl.Title.Replace("Var: ", "")]);
        }

        private void ActiveDocument_ContentControlOnExit(Word.ContentControl sender, ref bool e)
        {
            DeactivateContentControlOnExitEvent();

            if (sender.Type == Microsoft.Office.Interop.Word.WdContentControlType.wdContentControlText)
            {
                if (VarList[sender.Title.Replace("Var(Text): ", "")].Content.ToString() != sender.Range.Text)
                    VarList[sender.Title.Replace("Var(Text): ", "")].SetContent(sender.Range.Text);
            }
            else
            {
                VarList[sender.Title.Replace("Var(Image): ", "")].SetContent(sender);
            }

            ActivateContentControlOnExitEvent();
        }

        private void Application_DocumentOpen(Word.Document sender)
        {
            VarList = new VariableList<Variable>();

            foreach (Word.ContentControl cc in this.Application.ActiveDocument.ContentControls)
            {
                if (cc.Title.StartsWith("Var(Text): "))
                {
                    if (!VarList.Keys.Contains<string>(cc.Title.Replace("Var(Text): ", "")))
                    {                        
                        Variable var = new TextVariable(cc.Title.Replace("Var(Text): ", ""), cc.Range.Text);
                        VarList.Add(var);
                    }
                }
                else if (cc.Title.StartsWith("Var(Image): "))
                {
                    if (!VarList.Keys.Contains<string>(cc.Title.Replace("Var(Image): ", "")))
                    {                     
                        Variable var = new ImageVariable(cc.Title.Replace("Var(Image): ", ""));
                        var.SetContent(cc);
                        VarList.Add(var);
                    }
                }
            }

            VarLists[this.Application.ActiveDocument] = VarList;
        }

        private void Application_DocumentChange()
        {
            if (!VarLists.Keys.Contains<Word.Document>(this.Application.ActiveDocument))
            {
                this.VarList.ItemChanged += new TemplateAddIn.VariableEvent(UpdateVariableControls);
                this.VarList.ItemAdded += new ListEvent(VarList_ItemAdded);
                this.VarList.ItemRemoved += new ListEvent(VarList_ItemRemoved);
                VarLists.Add(this.Application.ActiveDocument, VarList);
            }

            VarList = VarLists[this.Application.ActiveDocument];
        }

        void Application_DocumentBeforeClose(Microsoft.Office.Interop.Word.Document Doc, ref bool Cancel)
        {
            VarLists.Remove(Doc);
        }
        #endregion

        /// <summary>
        /// Insere um Content Control para a variável passada por parâmetro.
        /// </summary>
        /// <param name="pVar">Variável que definirá o controle a ser inserido.</param>
        public void InsertVariableControl(Variable pVar)
        {
            InsertVariableControl(pVar, this.Application.Selection.Range);
        }

        /// <summary>
        /// Insere um Content Control para a variável passada por parâmetro.
        /// </summary>
        /// <param name="pVar">Variável que definirá o controle a ser inserido.</param>
        private void InsertVariableControl(Variable pVar, Word.Range pRange)
        {
            ICreateContentControl iCCC = ICreateContentControlFactory.CreateICCC(pVar);

            iCCC.CreateContentControl(pVar, this.Application.Selection.Range, this.Application);
        }

        public void InsertVariableControls(Variable pVar)
        {
            string[] words = Application.Selection.Range.Text.Split(' ');

            Application.Selection.Start = 0;
            Application.Selection.End = 0;

            for (int i = 1; i <= Application.ActiveDocument.Content.Words.Count; i++)
            {
                if (Application.ActiveDocument.Content.Words[i].Text != null && Application.ActiveDocument.Content.Words[i].Text.Trim() != "" && Application.ActiveDocument.Content.Words[i].Text != "\r")
                {
                    if (Application.ActiveDocument.Content.Words[i].Text.ToLower().Trim() == words[0].ToLower().Trim())
                    {
                        for (int j = 0; j < words.Length; j++)
                        {
                            if (Application.ActiveDocument.Content.Words[i + j].Text.ToLower().Trim() != words[j].ToLower().Trim())
                            {
                                break;
                            }

                            if (j == words.Length - 1)
                            {
                                object start, end;
                                start = (object)Application.ActiveDocument.Content.Words[i].Start;
                                end = (object)Application.ActiveDocument.Content.Words[i + (words.Length > 1 ? j : 0)].End;

                                Word.Range range = Application.ActiveDocument.Range(ref start, ref end);

                                InsertVariableControl(pVar, range);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Remove todos os Content Controls da área selecionada.
        /// </summary>
        /// <param name="pDeleteContents">Um boleano que define se o conteúdo dos
        /// Content Controls deve ser removido.</param>
        public void RemoveVariableControl(bool pDeleteContents)
        {
            foreach (Word.ContentControl cc in this.Application.Selection.Range.ContentControls)
            {
                if (cc.Title.StartsWith("Var"))
                {
                    ContentControl controlToRemove=null;

                    foreach (ContentControl fcc in this.varList[cc.Title.Remove(0, cc.Title.IndexOf(" ")).Trim()].ContentControlList)
                    {
                        if ((fcc.Range.Start == cc.Range.Start) && (fcc.Range.End == cc.Range.End))
                        {
                            controlToRemove = fcc;
                            break;
                        }
                    }

                    if (controlToRemove != null)
                    {
                        this.varList[cc.Title.Remove(0, cc.Title.IndexOf(" ")).Trim()].ContentControlList.Remove(controlToRemove);
                    }

                    cc.Delete(pDeleteContents);
                }
            }
        }

        public void UpdateVariableControls(Variable pVar)
        {
            if (VariableModified != null)
                VariableModified(pVar);
        }

        /// <summary>
        /// This Method removes an variable from the list
        /// </summary>
        /// <param name="pVar"></param>
        /// <param name="pDeleteContents"></param>
        public void RemoveVariable(Variable pVar, bool pDeleteContents)
        {
            VarList.Remove(pVar);
            DeleteVariableControls(pVar, pDeleteContents);
        }

        /// <summary>
        /// This Method removes the controls associated with the passed variable
        /// </summary>
        /// <param name="pVar"></param>
        /// <param name="pDeleteContents"></param>
        public void DeleteVariableControls(Variable pVar, bool pDeleteContents)
        {
            foreach (Word.ContentControl cc in pVar.ContentControlList)
                cc.Delete(pDeleteContents);
        }

        public void ActivateContentControlOnExitEvent()
        {
            HandleContentControlOnExitEvent = true;
        }

        public void DeactivateContentControlOnExitEvent()
        {
            HandleContentControlOnExitEvent = false;
        }
    }
}
